package de.recipeminer.tools;

import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import org.apache.log4j.Logger;
import org.jruby.CompatVersion;
import org.jruby.RubyInstanceConfig;
import org.jruby.embed.InvokeFailedException;
import org.jruby.embed.LocalContextScope;
import org.jruby.embed.LocalVariableBehavior;
import org.jruby.embed.ScriptingContainer;


import java.io.File;
import java.util.List;


public class RubyScriptContainer {
    public static Logger logger = Logger.getLogger(RubyScriptContainer.class);
    private static ScriptingContainer defaultInstance = null;

    /**
     * Returns Ruby Runtime Container which is persistent over the complete program
     * execution. It remembers loaded files and changed global variables. Local variables
     * passed to this container persist across multiple evaulation commands.
     *
     * @return the default scripting container
     */
    public static ScriptingContainer getDefaultContainer() {
        if (defaultInstance == null) {

            defaultInstance = new ScriptingContainer(LocalContextScope.THREADSAFE,
                    LocalVariableBehavior.PERSISTENT);
            initDefaultContainer();
        }
        return defaultInstance;
    }

    /**
     * Creates a transient scripting container unaware of modifications in the default
     * container. This container does not persist local variables passed to it accross
     * different evaluations and will be subject to garbage-collection.
     *
     * @return a temporary scripting container
     */
    public static ScriptingContainer getTransientContainer() {
        ScriptingContainer container = new ScriptingContainer(LocalContextScope.SINGLETHREAD,
                LocalVariableBehavior.TRANSIENT);
        container.setCompatVersion(CompatVersion.RUBY1_9);
        return container;
    }

    private static void initDefaultContainer() {
        defaultInstance = new ScriptingContainer(LocalContextScope.THREADSAFE,
                LocalVariableBehavior.PERSISTENT);
        RubyInstanceConfig defaultInstanceConfig = defaultInstance.getProvider().getRubyInstanceConfig();
        defaultInstance.setCompatVersion(CompatVersion.RUBY1_9);
        if (Config.Environment.DEVELOPMENT.isActive() || Config.Environment.TEST.isActive()) {
            logger.info("Enabling JRuby Debug mode");
            defaultInstanceConfig.setDebug(true);
            defaultInstanceConfig.setObjectSpaceEnabled(true);
        }
        List<String> loadPaths = Lists.newLinkedList();
        loadPaths.add(Tools.getRubySourcePath());
        String home = defaultInstance.getHomeDirectory();
        if (home != null) {
            String binPath = Joiner.on(File.separator).join(home, "bin");
            loadPaths.add(binPath);
        }
        defaultInstance.getLoadPaths().addAll(0, loadPaths);
        defaultInstance.getProvider().getRubyInstanceConfig().setScriptFileName("<JRubyEmbedScript>");
        try {
            defaultInstance.runScriptlet("require 'main/init'");
        } catch (InvokeFailedException ife) {
            logger.error("Error loading init script", ife);
            throw ife;
        }
    }
}
